#include <buola/gui.h>

#include <buola/algorithm/container.h>
#include <buola/gui/cpropertyfield.h>
#include <buola/gui/cpropertyeditor.h>
#include <buola/image/cgc.h>
#include <buola/gui/cconfig.h>
#include <buola/image/cgradient.h>

#include <buola/widgets/cscrollbar.h>
#include <buola/widgets/cpropertytable.h>
#include <buola/widgets/crulerbox.h>
#include <buola/widgets/ctheme.h>

namespace buola { namespace gui {

void CPropertyTable::SField::InitRow(SRow *pRow)
{
    mType->InitValue(*pRow->mValues[mValueIndex]);
    pRow->mFlags[mFlagsIndex]=FIELD_NONE;
    if(mTypeIndex>=0)
        pRow->mTypes[mTypeIndex]=mType;
}

void CPropertyTable::SGroup::OnFieldAdded(CPropertyType *pType)
{
    for(int i=0;i<mRows.size();i++)
    {
        pType->InitValue(construct_back(mRows[i]->mValues));
        mRows[i]->mFlags.push_back(FIELD_NONE);
    }
}

void CPropertyTable::SGroup::OnVariantFieldAdded(CPropertyType *pDefaultType)
{
    for(int i=0;i<mRows.size();i++)
    {
        pDefaultType->InitValue(construct_back(mRows[i]->mValues));
        mRows[i]->mFlags.push_back(FIELD_NONE);
        mRows[i]->mTypes.push_back(pDefaultType);
    }
}

void CPropertyTable::SGroup::OnFieldsRemoved()
{
    for(int i=0;i<mRows.size();i++)
    {
        mRows[i]->mValues.clear();
        mRows[i]->mFlags.clear();
        mRows[i]->mTypes.clear();
    }
}

CPropertyTable::CPropertyTable()
    :   mIsPosValid(false),
        mIsDrawing(true),
        mButtonSelected(nullptr),
        mButtonPressed(nullptr),
        mIconStyle(CIcon::MEDIUM),
        mNextValueIndex(0),
        mNextFlagsIndex(0),
        mNextTypeIndex(0)
    ,   mScrollPos(0,0)
{
    mSelected.mRow=nullptr;
    mEditing.mRow=nullptr;

    AddGroup(L"default",GROUP_NOHEADER);
    SetBackColor({1.0,1.0,1.0});

    SetPointer(CPointer::STOCK_DEFAULT);

    mHScroll=new CScrollBar();
    mHScroll->eChanged.Connect(&CPropertyTable::OnHScroll,this,_1);
    mHScroll->SetStyle(CScrollBar::STYLE_HORIZONTAL);
    mHScroll->SetRange(0,15);
    mHScroll->SetStep(2,10);
    mHScroll->SetValue(0,false);

    mVScroll=new CScrollBar();
    mVScroll->eChanged.Connect(&CPropertyTable::OnVScroll,this,_1);
    mVScroll->SetRange(0,15);
    mVScroll->SetStep(2,10);
    mVScroll->SetValue(0,false);

    ///\todo
    //attach_scroll_bars(mHScroll,mVScroll);

    mRuler=new CRulerBox;
    ///\todo
    //attach_ruler_bars(mRuler,nullptr);
    FillRuler();
    mRuler->Show();
    mRuler->eMoved.Connect(&CPropertyTable::OnRulerMoved,this,_1,_2);
}

CPropertyTable::~CPropertyTable()
{
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
////////////////////////// Interface //////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

TID CPropertyTable::AddField(CPropertyType *pType,const std::wstring &pTitle,
                    double pW)
{
    SField *lField=new SField;

    lField->mFlags=FIELD_NONE;
    lField->mType=pType;
    lField->mTitle=pTitle;
    lField->mW=pW;
    lField->mMinW=50.0;

    lField->mValueIndex=mNextValueIndex++;
    lField->mFlagsIndex=mNextFlagsIndex++;
    lField->mTypeIndex=-1;

    mFieldsHash[pTitle]=lField;
    mFields.emplace_back(lField);

    for(int i=0;i<mGroups.size();i++)
    {
        mGroups[i]->OnFieldAdded(pType);
    }

    mIsPosValid=false;
    FillRuler();
    Refresh();

    return mFields.size()-1;
}

TID CPropertyTable::AddField(const std::wstring &pType,const std::wstring &pTitle,
                    double pW)
{
    return AddField(CPropertyType::GetType(pType),pTitle,pW);
}

TID CPropertyTable::AddVariantField(CPropertyType *pType,const std::wstring &pTitle,
                    double pW)
{
    SField *lField=new SField;

    lField->mFlags=FIELD_VARIANT;
    lField->mType=pType;
    lField->mTitle=pTitle;
    lField->mW=pW;
    lField->mMinW=50.0;

    lField->mValueIndex=mNextValueIndex++;
    lField->mFlagsIndex=mNextFlagsIndex++;
    lField->mTypeIndex=mNextTypeIndex++;

    mFieldsHash[pTitle]=lField;
    mFields.emplace_back(lField);

    for(int i=0;i<mGroups.size();i++)
    {
        mGroups[i]->OnVariantFieldAdded(pType);
    }

    mIsPosValid=false;
    FillRuler();
    Refresh();

    return mFields.size()-1;
}

TID CPropertyTable::AddVariantField(const std::wstring &pType,const std::wstring &pTitle,
                    double pW)
{
    return AddVariantField(CPropertyType::GetType(pType),pTitle,pW);
}

void CPropertyTable::RemoveAllFields()
{
    mSelected.mRow=nullptr;
    if(mEditing.mRow)
        EndEditing();

    mFieldsHash.clear();
    mFields.clear();

    for(int i=0;i<mGroups.size();i++)
    {
        mGroups[i]->OnFieldsRemoved();
    }

    mIsPosValid=false;
    FillRuler();
    Refresh();
}

TID CPropertyTable::AddGroup(const std::wstring &pName,EGroupFlags pFlags)
{
    SGroup *lGroup=new SGroup;
    lGroup->mID=mGroups.size();
    lGroup->mName=pName;
    lGroup->mFlags=pFlags&GROUP_STYLE;

    mGroups.emplace_back(lGroup);

    mIsPosValid=false;

    return lGroup->mID;
}

void CPropertyTable::RemoveAllGroups()
{
    mGroups.erase(mGroups.begin()+1,mGroups.end());

    mIsPosValid=false;
}

void CPropertyTable::SetGroupFlags(TID pGroup,EGroupFlags pFlags)
{
    mGroups[pGroup]->mFlags&=~GROUP_STYLE;
    mGroups[pGroup]->mFlags|=pFlags&GROUP_STYLE;
    mIsPosValid=false;
    Refresh();
}

void CPropertyTable::SetGroupName(TID pGroup,const std::wstring &pName)
{
    mGroups[pGroup]->mName=pName;
    mIsPosValid=false;
    Refresh();
}

CPropertyTable::SRow *CPropertyTable::AddRow(TID pGroup)
{
    SRow *lRow=new SRow;

    lRow->mGroup=pGroup;
    lRow->mFlags.resize(mNextFlagsIndex);
    construct_resize(lRow->mValues,mNextValueIndex);
    lRow->mTypes.resize(mNextTypeIndex);

    for(int i=0;i<mFields.size();i++)
    {
        mFields[i]->InitRow(lRow);
    }

    mGroups[pGroup]->mRows.emplace_back(lRow);

    mIsPosValid=false;

    Refresh();

    return lRow;
}

void CPropertyTable::RemoveRow(SRow *pRow)
{
    mSelected.mRow=nullptr;
    if(mEditing.mRow)
        EndEditing();
    SGroup &lGroup=*mGroups[pRow->mGroup];
    for(int i=0;i<lGroup.mRows.size();i++)
    {
        if(pRow==lGroup.mRows[i].get())
        {
            lGroup.mRows.erase(lGroup.mRows.begin()+i);
            break;
        }
    }

    mIsPosValid=false;
    Refresh();
}

void CPropertyTable::RemoveAllRows()
{
    mSelected.mRow=nullptr;
    if(mEditing.mRow)
        EndEditing();

    for(int i=0;i<mGroups.size();i++)
        mGroups[i]->mRows.clear();

        mIsPosValid=false;

    Refresh();
}

int CPropertyTable::GetRowCount(TID pGroup)
{
    return mGroups[pGroup]->mRows.size();
}

CPropertyTable::SRow *CPropertyTable::GetRow(int pIndex,TID pGroup)
{
    return mGroups[pGroup]->mRows[pIndex].get();
}

const UAny &CPropertyTable::GetCellValue(SRow *pRow,TID pField)
{
    return *pRow->mValues[mFields[pField]->mValueIndex];
}

const UAny &CPropertyTable::GetCellValue(SRow *pRow,const std::wstring &pField)
{
    return *pRow->mValues[mFieldsHash[pField]->mValueIndex];
}

void CPropertyTable::SetCellValue(SRow *pRow,TID pField,const UAny &pValue)
{
    *pRow->mValues[mFields[pField]->mValueIndex]=pValue;

    Refresh();
}

void CPropertyTable::SetCellValue(SRow *pRow,const std::wstring &pField,const UAny &pValue)
{
    *pRow->mValues[mFieldsHash[pField]->mValueIndex]=pValue;

    Refresh();
}

void CPropertyTable::SetCellType(SRow *pRow,TID pField,CPropertyType *pType)
{
    pRow->mTypes[mFields[pField]->mTypeIndex]=pType;

    Refresh();
}

void CPropertyTable::SetCellType(SRow *pRow,const std::wstring &pField,CPropertyType *pType)
{
    pRow->mTypes[mFieldsHash[pField]->mTypeIndex]=pType;

    Refresh();
}

void CPropertyTable::SetCellFlags(SRow *pRow,TID pField,EFieldFlags pFlags)
{
    pRow->mFlags[mFields[pField]->mFlagsIndex]=pFlags;

    Refresh();
}

void CPropertyTable::SetCellFlags(SRow *pRow,const std::wstring &pField,EFieldFlags pFlags)
{
    pRow->mFlags[mFieldsHash[pField]->mFlagsIndex]=pFlags;

    Refresh();
}

void CPropertyTable::EditCell(SRow *pRow,TID pField)
{
    StartEditing(pRow,mFields[pField].get());
}

void CPropertyTable::EditCell(SRow *pRow,const std::wstring &pField)
{
    StartEditing(pRow,mFieldsHash[pField]);
}

void CPropertyTable::CenterCell(SRow*,TID /*pField*/)
{
    ///\todo
//  CPoint_d lPoint=pField->mPos+pField->mSize/2-mRect.Size()/2;

//  mHScroll->SetPos((int)lPoint.x,false);
//  mVScroll->SetPos((int)lPoint.y,false);
}

void CPropertyTable::SetIconStyle(int pStyle)
{
    if(pStyle!=mIconStyle)
    {
        mIconStyle=pStyle;
        mIsPosValid=false;

        Refresh();
    }
}

CPropertyTable::SRow *CPropertyTable::GetSelRow()
{
    if(mSelected.mRow)
        return mSelected.mRow;
    else
        return nullptr;
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
///////////////////// Internal functions //////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

void CPropertyTable::DrawAll(img::CGC *pGC)
{
    DrawAll(pGC,CRect_d({0,0},Size()));
}

void CPropertyTable::DrawAll(img::CGC *pGC,const CRect_d &pRect)
{
    mIsDrawing=true;

    if(!mIsPosValid)
        PosAll();

    CPoint_d lPos(0,0);
    CSize_d lSize(16,mCellH);

    pGC->SetLineWidth(1.0);

    for(int i=0;i<mGroups.size();i++)
    {
        lPos.y=mGroups[i]->mYStart-mScrollPos.y;

        if(lPos.y>pRect.b||
            mGroups[i]->mYEnd-mScrollPos.y<pRect.t)
        {
            continue;
        }

        if(mGroups[i]->mRows.empty()&&(mGroups[i]->mFlags&GROUP_HIDEIFEMPTY))
            continue;

        if(!(mGroups[i]->mFlags&GROUP_NOHEADER))
        {
            img::CLinearGradient lPattern(CPoint_d(0,lPos.y+1),CPoint_d(0,lPos.y+mHeaderH-1));
//          lPattern.AddStop(img::rgb8(230,230,230),0.0);
//          lPattern.AddStop(img::rgb8(200,200,200),1.0);
            lPattern.AddStop(img::rgb8(218,223,232),0.0);
            lPattern.AddStop(img::rgb8(196,201,209),1.0);
            pGC->SetSource(lPattern);
            pGC->Path().Rect(CPoint_d(pRect.l,lPos.y),CSize_d(pRect.w(),mHeaderH));
            pGC->FillPath();
            pGC->Path().MoveTo(CPoint_d(0,lPos.y+0.5));
            pGC->Path().LineTo(CPoint_d(pRect.r,lPos.y+0.5));
            pGC->SetSource(img::rgb8(227,232,242));
            pGC->StrokePath();
            pGC->Path().MoveTo(CPoint_d(0,lPos.y+mHeaderH-0.5));
            pGC->Path().LineTo(CPoint_d(pRect.r,lPos.y+mHeaderH-0.5));
            pGC->SetSource(img::rgb8(176,181,188));
            pGC->StrokePath();
            pGC->SetStockFont(L"smallbold");
            pGC->SetSource(img::rgb8(150,150,150));
            double lLineY=lPos.y+floor(mHeaderH/2)+0.5;
            double lTextW=pGC->GetTextExtents(mGroups[i]->mName).x;
            double lRightX=pRect.r-5;
            if(mGroups[i]->mFlags&GROUP_ADDBUTTON)
                lRightX-=mHeaderH;
            pGC->Path().MoveTo(CPoint_d(pRect.l+5,lLineY));
            pGC->Path().LineTo(CPoint_d(pRect.l+25,lLineY));
            pGC->Path().MoveTo(CPoint_d(pRect.l+35+lTextW,lLineY));
            pGC->Path().LineTo(CPoint_d(lRightX,lLineY));
            pGC->StrokePath();
            pGC->SetSource(img::rgb8(50,50,50));
//          pGC->SetSource(BLACK);
            pGC->DrawText(CPoint_d(30-mScrollPos.x,lPos.y+4),mGroups[i]->mName);
            if(mGroups[i]->mFlags&GROUP_ADDBUTTON)
            {
                pGC->SetSource(img::rgba8(0,0,0,50));
                pGC->Path().MoveTo(CPoint_d(pRect.r-mHeaderH-0.5,lPos.y));
                pGC->Path().LineTo(CPoint_d(pRect.r-mHeaderH-0.5,lPos.y+mHeaderH));
                pGC->StrokePath();
                pGC->SetSource(img::rgba8(255,255,255,50));
                pGC->Path().MoveTo(CPoint_d(pRect.r-mHeaderH+0.5,lPos.y));
                pGC->Path().LineTo(CPoint_d(pRect.r-mHeaderH+0.5,lPos.y+mHeaderH));
                pGC->StrokePath();
                CPoint_d lCenter(floor(pRect.r-mHeaderH/2),floor(lPos.y+mHeaderH/2));
                pGC->SetSource(img::rgba8(255,255,255,200));
                pGC->Path().Rect(CPoint_d(lCenter.x-1,lCenter.y-4),CSize_d(2,8));
                pGC->Path().Rect(CPoint_d(lCenter.x-4,lCenter.y-1),CSize_d(8,2));
                pGC->FillPath();
                pGC->SetSource(img::rgba8(0,0,0,200));
                pGC->Path().Rect(CPoint_d(lCenter.x-2,lCenter.y-5),CSize_d(2,8));
                pGC->Path().Rect(CPoint_d(lCenter.x-5,lCenter.y-2),CSize_d(8,2));
                pGC->FillPath();
                if(mGroups[i]->mFlags&GROUP_HLBUTTON)
                {
                    pGC->SetOperator(img::ECompOp::ADD);
                    pGC->SetSource(img::rgba8(255,255,255,20));
                    pGC->Path().Rect(CPoint_d(pRect.r-mHeaderH+1,lPos.y),CSize_d(mHeaderH,mHeaderH));
                    pGC->FillPath();
                    pGC->SetOperator(img::ECompOp::OVER);
                }
            }
            lPos.y+=mHeaderH;
        }

        for(int j=0;j<mGroups[i]->mRows.size();j++)
        {
            if(lPos.y>pRect.b||lPos.y+lSize.y<pRect.t)
            {
                lPos.y+=mCellH;
                continue;
            }

            if(mGroups[i]->mRows[j]->mRowI%2)
            {
                pGC->SetSource(img::rgb8(237,243,254));
                pGC->Path().Rect(CPoint_d(pRect.l,lPos.y),CSize_d(pRect.w(),lSize.y));
                pGC->FillPath();
            }

            for(int k=0;k<mFields.size();k++)
            {
                lPos.x=mFields[k]->mX-mScrollPos.x;
                lSize.x=mFields[k]->mW;
                if(lPos.x>pRect.r||lPos.x+lSize.x<pRect.l) continue;

                DrawCell(pGC,mGroups[i]->mRows[j].get(),k,CRect_d(lPos,lSize));
            }
            lPos.y+=mCellH;
        }

        for(int j=0;j<mFields.size();j++)
        {
            lPos.x=mFields[j]->mX-mScrollPos.x;
            lSize.x=mFields[j]->mW;
            if(lPos.x>pRect.r||lPos.x+lSize.x<pRect.l) continue;

            pGC->SetSource(img::rgb8(216,216,216));
            pGC->Path().MoveTo(CPoint_d(lPos.x+lSize.x-0.5,mGroups[i]->mYBase-mScrollPos.y));
            pGC->Path().LineTo(CPoint_d(lPos.x+lSize.x-0.5,mGroups[i]->mYEnd-mScrollPos.y));
            pGC->StrokePath();
        }
    }

    double lBottom=lPos.y;

    int lRowI=mLastRowI;
    for(;lPos.y<pRect.b;lPos.y+=lSize.y,lRowI++)
    {
        if(lRowI%2)
        {
            pGC->SetSource(img::rgb8(237,243,254));
            pGC->Path().Rect(CPoint_d(pRect.l,lPos.y),CSize_d(pRect.w(),lSize.y));
            pGC->FillPath();
        }
    }

    if(lBottom<pRect.b)
    {
        for(int j=0;j<mFields.size();j++)
        {
            lPos.x=mFields[j]->mX-mScrollPos.x;
            lSize.x=mFields[j]->mW;
            if(lPos.x>pRect.r||lPos.x+lSize.x<pRect.l) continue;

            pGC->SetSource(img::rgb8(216,216,216));
            pGC->Path().MoveTo(CPoint_d(lPos.x+lSize.x-0.5,lBottom));
            pGC->Path().LineTo(CPoint_d(lPos.x+lSize.x-0.5,pRect.b));
            pGC->StrokePath();
        }
    }

    mIsDrawing=false;
}

void CPropertyTable::DrawCell(img::CGC *pGC,SRow *pRow,TID pCol,const CRect_d &pRect)
{
    if(!mIsPosValid)
        PosAll();

    SField *lField=mFields[pCol].get();

    bool lSel=(mSelected.mRow==pRow&&mSelected.mField==lField);

    pGC->SetStockFont(L"small");
    pGC->SetSource(gConfig.mColors.Get(lSel?L"selection_text":L"edit_text"));

    lField->mType->Draw(*pRow->mValues[pCol],pGC,pRect);
}

CPropertyTable::SPosition CPropertyTable::GetCellAt(const CPoint_d &pPoint)
{
    CPoint_d lPoint(pPoint+mScrollPos);

    SPosition lReturn;

    lReturn.mGroup=nullptr;
    lReturn.mRow=nullptr;
    lReturn.mField=nullptr;

    for(int i=0;i<mFields.size();i++)
    {
        if(lPoint.x>=mFields[i]->mX&&lPoint.x<mFields[i]->mX+mFields[i]->mW)
        {
            lReturn.mField=mFields[i].get();
            break;
        }
    }

    for(int i=0;i<mGroups.size();i++)
    {
        if(mGroups[i]->mRows.empty()&&(mGroups[i]->mFlags&GROUP_HIDEIFEMPTY))
            continue;

        if(lPoint.y>mGroups[i]->mYEnd) continue;
        if(lPoint.y>mGroups[i]->mYStart)
            lReturn.mGroup=mGroups[i].get();
        if(lPoint.y<mGroups[i]->mYBase) break;

        int lRow=(int)((lPoint.y-mGroups[i]->mYBase)/mCellH);
        if(lRow<0) break;
        if(lRow>=mGroups[i]->mRows.size()) break;

        lReturn.mRow=mGroups[i]->mRows[lRow].get();
        return lReturn;
    }

    return lReturn;
}

void CPropertyTable::ShapeAll()
{
//Icon size
    if(GetStyle(STYLE_NOICON))
        mIconSize={0,0};
    else
        mIconSize=CSize_d(mIconStyle);

    img::PFont lFont=img::CFont::GetStock(L"small");

    mTextSize.x=Size().x/3;
    mTextSize.y=lFont->GetHeight();

    mCellH=mTextSize.y+4;
    mHeaderH=20;
}

void CPropertyTable::PosAll()
{
    ShapeAll();

    double lX=0;

    for(int i=0;i<mFields.size();i++)
    {
        mFields[i]->mX=lX;
        lX+=mFields[i]->mW;
    }

    int lScrollRange=(int)(lX-Size().x-1);

    if(lScrollRange<=0)
        mHScroll->SetRange(0,0);
    else
    {
        mHScroll->SetRange(0,lScrollRange);
        mHScroll->SetStep((int)mTextSize.y,(int)Size().x+1);
    }

    mRuler->Refresh();

    double lY=0;
    int lRowI=0;
    for(int i=0;i<mGroups.size();i++)
    {
        mGroups[i]->mYStart=lY;

        if(mGroups[i]->mRows.empty()&&(mGroups[i]->mFlags&GROUP_HIDEIFEMPTY))
            continue;
        if(!(mGroups[i]->mFlags&GROUP_NOHEADER))
        {
            lRowI++;
            lY+=mHeaderH;
        }
        mGroups[i]->mYBase=lY;
        for(int j=0;j<mGroups[i]->mRows.size();j++)
        {
            mGroups[i]->mRows[j]->mRowI=lRowI++;
            mGroups[i]->mRows[j]->mY=lY;
            lY+=mCellH;
        }
        mGroups[i]->mYEnd=lY;
    }
    mLastRowI=lRowI;

    mIsPosValid=true;
}

void CPropertyTable::Update()
{
    PosAll();
}

void CPropertyTable::FillRuler()
{
    mRuler->RemoveFields();

    for(int i=0;i<mFields.size();i++)
    {
        if(mFields[i]->mFlags&FIELD_HIDDEN) continue;
        mRuler->AddField(i,mFields[i]->mTitle,nullptr,mFields[i]->mW);
    }

    mRuler->Refresh();
}

void CPropertyTable::StartEditing(SRow *pRow,SField *pField)
{
    if(!mIsPosValid)
        PosAll();

    CPoint_d lPos=CPoint_d(pField->mX,pRow->mY)-mScrollPos;
    CSize_d lSize=CSize_d(pField->mW,mCellH);

    mEditing.mRow=pRow;
    mEditing.mField=pField;
    mEditor=pField->mType->GetEditor();
    mEditor->sEndEdit.Connect(&CPropertyTable::EndEditing,this);
    mEditor->Start(*pRow->mValues[pField->mValueIndex],this,CRect_d(lPos,CSize_d(lSize.x-1,lSize.y)),
            (pRow->mRowI%2)?img::rgb8(237,243,254):img::CColor(1.0,1.0,1.0));
}

void CPropertyTable::EndEditing()
{
    mEditor->Finish(*mEditing.mRow->mValues[mEditing.mField->mValueIndex]);
    delete mEditor;
    sChanged(mEditing.mRow,mEditing.mField,
            *mEditing.mRow->mValues[mEditing.mField->mValueIndex]);
    mEditing.mRow=nullptr;
    Refresh();
}

///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
/////////////////////// Event handlers ////////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////

void CPropertyTable::OnExpose(const CExposeEvent &pE)
{
    img::CGC *lGC=pE.mGC;
    DrawAll(lGC,pE.mRect);
}

void CPropertyTable::OnHScroll(int pPos)
{
    //int lScrollBy=(int)mScrollPos.x-pPos;
    mScrollPos.x=pPos;
    ///\todo
//    if(lScrollBy&&!mIsDrawing)
//        ScrollBy(CPoint_d(lScrollBy,0));
}

void CPropertyTable::OnVScroll(int pPos)
{
    //int lScrollBy=(int)mScrollPos.y-pPos;
    mScrollPos.y=pPos;
    ///\todo
//    if(lScrollBy&&!mIsDrawing)
//        ScrollBy(CPoint_d(0,lScrollBy));
}

void CPropertyTable::OnButtonDown(const CMouseEvent &pE)
{
    if(mEditing.mRow)
    {
        EndEditing();
    }

    if(pE.mButton==EMouseButton::LEFT)
    {
        if(mButtonSelected)
        {
            mButtonPressed=mButtonSelected;
        }
        else
        {
            SPosition lPos=GetCellAt(pE.mPoint);

            if(lPos.mRow&&lPos.mField)
            {
                if(mSelected.mRow!=lPos.mRow||mSelected.mField!=lPos.mField)
                {
//                     img::CGC *lGC=StartPainting();
//                     SPosition lOld=mSelected;
//                     mSelected=lPos;
//                     if(lOld.mValid)
//                     {
//                         DrawCell(lGC,lOld.mRow,lOld.mCol);
//                     }
//                     DrawCell(lGC,lPos.mRow,lPos.mCol);
//                     EndPainting(lGC);

                    mSelected=lPos;
                    Refresh();
                }
                if((mEditing.mRow!=lPos.mRow||mEditing.mField!=lPos.mField)&&
                        !(lPos.mField->mFlags&FIELD_READONLY))
                {
                    StartEditing(lPos.mRow,lPos.mField);
                }
            }
            else if(mSelected.mRow)
            {
//                 img::CGC *lGC=StartPainting();
//                 SPosition lOld=mSelected;
//                 mSelected.mValid=false;
//                 DrawCell(lGC,lOld.mRow,lOld.mCol);
//                 EndPainting(lGC);

                mSelected.mRow=nullptr;
                Refresh();
            }
        }
    }
}

void CPropertyTable::OnButtonUp(const CMouseEvent &pE)
{
    if(pE.mButton==EMouseButton::LEFT)
    {
        if(mButtonPressed&&mButtonPressed==mButtonSelected)
        {
            SRow *lRow=AddRow(mButtonPressed->mID);
            sRowAdded(lRow,mButtonPressed->mID);
        }

        mButtonPressed=nullptr;
    }
}

//void CPropertyTable::OnDoubleClick(CMouseEvent *pE)
//{
/*  if(pE->mButton==EMouseButton::LEFT)
    {
        mDragging=false;
        mSelecting=false;
        Field *lItem=GetItemAt(pE->mPoint);

        if(lItem)
        {
            OnItemDblClk(lItem);
        }
    }
*/
//}

void CPropertyTable::OnMouseMove(const CMouseEvent &pE)
{
    SPosition lPos=GetCellAt(pE.mPoint);

    SGroup *lNewButtonSelected=nullptr;

    if(lPos.mGroup&&!lPos.mRow)
    {
        if(pE.mPoint.x>Size().x-20&&(lPos.mGroup->mFlags&GROUP_ADDBUTTON))
        {
            lNewButtonSelected=lPos.mGroup;
        }
    }

    if(mButtonSelected!=lNewButtonSelected)
    {
        if(mButtonSelected)
            mButtonSelected->mFlags&=~GROUP_HLBUTTON;
        mButtonSelected=lNewButtonSelected;
        if(mButtonSelected)
            mButtonSelected->mFlags|=GROUP_HLBUTTON;
        Refresh();
    }
}

void CPropertyTable::OnMouseWheel(const CMouseEvent &pE)
{
    if(pE.mScrollY!=0.0)
        mVScroll->Scroll(pE.mScrollY);
}

void CPropertyTable::OnSize(const CGeometryEvent &pE)
{
    mIsPosValid=false;

//  if(mEditing)
//  {
//      mEditing->mField->EndEditing(mEditing->mValue);
//      mEditing->mField->StartEditing(mEditing->mValue,this,
//      CPoint_d(mEditing->mPos.x-mScrollPos.x+mTextSize.x+1,
//              mEditing->mPos.y-mScrollPos.y),
//      CSize_d(mEditing->mSize.x-1-mTextSize.x,mEditing->mSize.y-1));
//  }
}

void CPropertyTable::OnStyleChanged(TStyle)
{
//  Refresh();
}

void CPropertyTable::OnRulerMoved(TID pID,double pSize)
{
    mFields[pID]->mW=pSize;

    PosAll();
    Refresh();
}

/*namespace gui*/ } /*namespace buola*/ }
